/* ***** BEGIN LICENSE BLOCK *****
 *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Save File to.
 *
 * The Initial Developer of the Original Code is
 * Atte Kemppilä.
 * Portions created by the Initial Developer are Copyright (C) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 * 
 * ***** END LICENSE BLOCK ***** */


const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/Services.jsm");

Cu.import("resource://savefileto/common.jsm");
Cu.import("resource://savefileto/constants.jsm");
Cu.import("resource://savefileto/DataSource.jsm");
Cu.import("resource://savefileto/Entry.jsm");
Cu.import("resource://savefileto/savefileto.jsm");
Cu.import("resource://savefileto/Transformer.jsm");

const atomSvc = Cc["@mozilla.org/atom-service;1"].getService(Ci.nsIAtomService);
const clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
const dragSvc = Cc["@mozilla.org/widget/dragservice;1"].getService(Ci.nsIDragService);


const FLAVOR_SAVEFILETO_INDEXES = "application/x.org.mozdev.savefileto.indexes";  // rfc 4288
const FLAVOR_SAVEFILETO_ENTRIES = "application/x.org.mozdev.savefileto.entries";  // rfc 4288


var prefwindow =
{
    panes: ["main"].concat(TYPES),
    
    /** current prefpane name (prefwindow.panes) */
    pane: null,
    
    _treeView: {},
    
    /** current type */
    get type()
    {
        var pane = this.pane;
        return ((TYPES.indexOf(pane) != -1) ? pane : null);
    },
    
    /** is current type enabled */
    get enabled()
    {
        var type = this.type;
        return (type ? this.isEnabled(type) : false);
    },
    
    /** current type's tree view */
    get treeView()
    {
        var type = this.type;
        return (type ? this._treeView[type] : null);
    },
    
    onLoad: function()
    {
        this.bundle = document.getElementById("bundle");
        this.prefs = Services.prefs.getBranch(EXT_PREF_BRANCH);
        
        var instantApply = document.documentElement.instantApply;
        
        for each (var type in TYPES)
        {
            // data source
            // dataSource must be disposed (handled by treeView.dispose() on unload)
            let prefName = EXT_PREF_BRANCH + type + ".entries";
            let dataSource = this._createDataSource(type, instantApply);
            
            // tree view
            let tree = document.getElementById("tree_" + type + "_entries");
            let treeView = new DataSourceTreeView(dataSource);
            tree.view = this._treeView[type] = treeView;
            
            // tree controller
            let controller = new TreeController(treeView);
            tree.controllers.appendController(controller);
            
            // tree drag'n'drop
            let dnd = new TreeDragAndDrop(tree, treeView);
            treeView.dnd = dnd;
            
            window.addEventListener("unload", function() { treeView.dispose(); }, false);
        }
        
        // entry controller
        var controller = new EntryController();
        window.controllers.appendController(controller);
        
        // prefpane select listener
        var self = this;
        document.documentElement._selector.addEventListener("select", function(e) { self.onPaneSelect(e); }, false);
        
        this.pane = this._resolvePaneFromElement(document.documentElement.currentPane);
        this._updateUi(this.pane);
        
        // don't know why, but update doesn't work until a delay
        // goUpdateCommand() can't seem to find the controller the first time
        // the first call is still done to disable all the commands to avoid flicker
        this._updateCommands();
        callLater(0, this, this._updateCommands);
    },
    
    onDialogAccept: function()
    {
        for each (var type in TYPES)
            this._treeView[type].dataSource.flush();
        
        return true;
    },
    
    onPaneSelect: function(e)
    {
        var node = e.originalTarget;
        var pane = this.panes[node.selectedIndex];
        
        this.pane = pane;
        this._updateUi(this.pane);
        this._updateCommands();
    },
    
    onTypeEnabledChange: function(e)
    {
        var pref = e.target;
        var type = this._resolvePaneFromElement(pref);
        var enabled = this.isEnabled(type);
        
        if (! enabled)
            this._treeView[type].clearSelection();
        
        this._updateUi(type);
        
        if (type == this.type)
            this._updateCommands();
    },
    
    onTreeSelect: function(e)
    {
        this._updateCommands();
    },
    
    onTreeKeyPress: function(e)
    {
        if (e.charCode == e.DOM_VK_SPACE)
            goDoCommand("cmd_toggleMenu");
    },
    
    onTreeDoubleClick: function(e)
    {
        var result = this.treeView.getCellAt(e.clientX, e.clientY);
        var col = result.col;
        
        if (col && (this.treeView.getColumnType(col) != "menu"))
            goDoCommand("cmd_editFolder");
    },
    
    isEnabled: function(type)
    {
        var pref = document.getElementById("pref_" + type + "_enabled");
        return (pref ? pref.value : false);
    },
    
    clearRecent: function()
    {
        savefileto.cleanUp(true);
    },
    
    /**
     * Creates caching data source.
     * Data source must be disposed.
     */
    _createDataSource: function(type, writeThrough)
    {
        var mainDataSource = savefileto.mainDataSource[type];
        
        var transformers =
        {
            folder: null,
            item: savefileto.commandLabelTransformer,
            named: savefileto.namedFolderTransformer,
            recent: null,
            separator: null
        }
        var transformer =
            new ArrayTransformer(
                new SwitchTransformer("type", transformers),
                true);
        
        var dataSource =
            new CachingDataSource(
                new TransformingDataSource(mainDataSource, transformer),
                writeThrough);
        
        return dataSource;
    },
    
    _resolvePaneFromElement: function(elem)
    {
        var id = elem.id;
        var start = id.indexOf("_");
        var end = id.indexOf("_", start + 1);
        if (end == -1)
            end = id.length;
        var type = id.substring(start + 1, end);
        return type;
    },
    
    _updateUi: function(pane)
    {
        if (TYPES.indexOf(pane) != -1)
        {
            var type = pane;
            var enabled = this.isEnabled(type);
            
            document.getElementById("tree_" + type + "_entries").disabled = (! enabled);
            document.getElementById("btn_" + type + "_addEntry").disabled = (! enabled);
        }
    },
    
    _updateCommands: function()
    {
        window.updateCommands("tree-select");
    }
}
